//
//  Image4DSimple.m
//  V3d_Cocoa
//
//  Created by yang liang on 11-3-28.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "Image4DSimple.h"


@implementation Image4DSimple

-(id) initialize
{
	data1d = 0;
	sz0 = sz1 = sz2 = sz3 = 0;
	sz_time = 0;
	datatype = V3D_UNKNOWN;
	timepacktype = TIME_PACK_NONE;
	imgSrcFile[0] = '\0';
	b_error = 0;
	rez_x = rez_y = rez_z = 1;
	
	origin_x = origin_y = origin_z = 0;
	p_customStruct = 0;
	
	valid_zslicenum = 0;
	return self;
}

-(void) setXDim:(V3DLONG) v
{
	sz0 = v;
}
-(void) setYDim:(V3DLONG) v
{
	sz1 = v;
}
-(void) setZDim:(V3DLONG) v
{
	sz2 = v;
}
-(void) setCDim:(V3DLONG) v
{
	sz3 = v;
}
-(void) setTDim:(V3DLONG) v
{
	sz_time = v;
}

-(BOOL) setValidZSliceNum:(V3DLONG) v
{
	if (v==0 && sz2==0) {valid_zslicenum=0; return YES;}
	if (v>=0 && v<sz2) //in this case sz2>0
	{valid_zslicenum = v; return YES;} 
	else 
		return NO;
}
-(BOOL) setPreValidZSliceNum:(V3DLONG) v
{
	if (v==0 && sz2==0) {prevalid_zslicenum=0; return YES;}
	if (v>=0 && v<sz2) //in this case sz2>0
	{prevalid_zslicenum = v; return YES;} 
	else
		return NO;
}

-(void) setDataType:(ImagePixelType) v
{
	datatype = v;
}
-(void) setTimePackType:(TimePackType) v
{
	timepacktype = v;
}

-(BOOL) setNewRawDataPointer:(unsigned char *) p
{
	if (!p) return NO; 
	if (data1d) 
		free(data1d); 
	data1d = p; 
	return YES;
}
-(void) setRawDataPointerToNull
{
	data1d = 0;
}
-(void) deleteRawDataAndSetPointerToNull
{
	if (data1d) {free(data1d); data1d = 0;}
}
-(void) setRawDataPointer:(unsigned char *) p
{
	data1d = p;
}

-(BOOL) setRezX:(double) a
{
	if (a<=0) return NO; 
	rez_x = a; 
	return YES;
}
-(BOOL) setRezY:(double) a
{
	if (a<=0) return NO; 
	rez_y = a; 
	return YES;
}
-(BOOL) setRezZ:(double) a
{
	if (a<=0) return NO; 
	rez_z = a; 
	return YES;
}

-(void) setOriginX:(double) a
{
	origin_x = a;
}
-(void) setOriginY:(double) a
{
	origin_y = a;
}
-(void) setOriginZ:(double) a
{
	origin_z = a;
}

-(void) setCustomStructPointer:(void*) a
{
	p_customStruct = a;
}
-(void*) customStructPointer
{
	return p_customStruct;
}
-(BOOL) isValidCustomStructPointer
{
	return (p_customStruct!=0)?YES:NO;
}

-(BOOL) setData:(unsigned char *) p withImage:(Image4DSimple *) image
{
	BOOL result = [self setData:p withX:image->sz0 andY:image->sz1 andZ:image->sz2 andC:image->sz3 andPixelType:image->datatype];
	return result;
}
-(BOOL) setData:(unsigned char *) p withX:(V3DLONG) s0 andY:(V3DLONG) s1 andZ:(V3DLONG) s2 andC:(V3DLONG) s3 andPixelType:(ImagePixelType) dt
{
	if(p && s0>0 && s1>0 && s2>0 && s3>0 && (dt==V3D_UINT8 || dt==V3D_UINT16 || dt==V3D_FLOAT32))
		if([self setNewRawDataPointer:p])
		{
			[self setXDim:s0];
			[self setYDim:s1];
			[self setZDim:s2];
			[self setCDim:s3];
			[self setDataType:dt];
			return YES;
		}
	return NO;
}

-(BOOL) setFileName:(const char *) myfile
{
	if (!myfile) return NO;
	V3DLONG clen=1023;
	V3DLONG i;
	for (i=0;i<clen;i++)
	{
		if (myfile[i]!='\0')
		{
			imgSrcFile[i] = myfile[i];
		}
		else
		{
			imgSrcFile[i] = myfile[i];
			break;
		}
	}
	imgSrcFile[i]='\0';
	return YES;
}
-(const char *) fileName
{
	return imgSrcFile;
}

-(void) loadImage:(const char *) filename
{
	[self cleanExistData];
	strcpy(imgSrcFile,filename);
	V3DLONG *tmp_sz = 0;
	int tmp_datatype = 0;
	//int pixelnbits = 1;
	char * curFileSurfix = getSurfix(imgSrcFile);
	NSLog(@"The current input file has the surffix [%s] \n",curFileSurfix);
	if(strcasecmp(curFileSurfix, "tif") == 0 || strcasecmp(curFileSurfix, "tiff") == 0)
	{
		NSLog(@"Now try to use libtiff to read tiff...\n");
		if(loadTif2Stack(filename, &data1d, &tmp_sz, &tmp_datatype))
		{
			NSLog(@"Error happens in tiff file reading.\n");
			b_error = 1;
		}
	}
	else 
	{
		NSLog(@"The file is not supported in this version.\n");
		return;
	}
	switch (tmp_datatype)
	{
		case 1:
			datatype = V3D_UINT8;
			break;
			
		case 2: 
			datatype = V3D_UINT16;
			break;
			
		case 4:
			datatype = V3D_FLOAT32; //FLOAT32;
			break;
			
		default:
			NSLog(@"The data type is not UINT8, UINT16 or FLOAT32. Something wrong with the program, -- should NOT display this message at all. Check your program. \n");
			if (tmp_sz) {free(tmp_sz); tmp_sz=0;}
			return;
	}
	
	sz0 = tmp_sz[0];
	sz1 = tmp_sz[1];
	sz2 = tmp_sz[2];
	sz3 = tmp_sz[3]; //no longer merge the 3rd and 4th dimensions
	
	/* clean all workspace variables */
	
	if (tmp_sz) {free(tmp_sz); tmp_sz=0;}
	
	return;

}


-(BOOL) createImageWithX:(V3DLONG) s0 andY:(V3DLONG) s1 andZ:(V3DLONG) s2 andC:(V3DLONG) s3 andPixelType:(ImagePixelType) dt
{
	if (s0<=0 || s1<=0 || s2<=0 || s3<=0) return NO; //note that for this sentence I don't change b_error flag
	if (data1d) {free(data1d); data1d=0; sz0=0; sz1=0; sz2=0;sz3=0; datatype=V3D_UNKNOWN;}
	switch (dt)
	{
		case V3D_UINT8:
			data1d = (unsigned char*)Guarded_Malloc(s0*s1*s2*s3,"createImage");
			if (!data1d) {b_error=1;return NO;}
			break;
		case V3D_UINT16:
			data1d = (unsigned char*)Guarded_Malloc(s0*s1*s2*s3*2,"createImage");
			if (!data1d) {b_error=1;return NO;}
			break;
		case V3D_FLOAT32:
			data1d = (unsigned char*)Guarded_Malloc(s0*s1*s2*s3*4,"createImage");
			if (!data1d) {b_error=1;return NO;}
			break;
		default:
			b_error=1;
			return NO;
			break;
	}
	sz0=s0; sz1=s1; sz2=s2;sz3=s3; datatype=dt; b_error=0; //note that here I update b_error
	return YES;
}
-(void) createBlankImageWithX:(V3DLONG) s0 andY:(V3DLONG) s1 andZ:(V3DLONG) s2 andC:(V3DLONG) s3 andDataType:(int) dt
{
	if (s0<=0 || s1<=0 || s2<=0 || s3<=0)
	{
		NSLog(@"Invalid size parameters in createBlankImage(). Do nothing. \n");
		return;
	}
	if (dt!=1 && dt!=2 && dt!=4)
	{
		NSLog(@"Invalid image datatype parameter in createBlankImage(). Do nothing. \n");
		return;
	}
	
	//otherwise good to go
	
	[self cleanExistData]; /* note that this variable must be initialized as NULL. */
	
	strcpy(imgSrcFile, "Untitled_blank.raw");
	
	//==============
	
	switch (dt)
	{
		case 1:
			datatype = V3D_UINT8;
			break;
			
		case 2:
			datatype = V3D_UINT16;
			break;
			
		case 4:
			datatype = V3D_FLOAT32;
			break;
			
		default:
			NSLog(@"Something wrong with the program in My4DImageSimple::createBlankImage(), -- should NOT display this message at all. Check your program. \n");
			b_error=1;
			return;
	}
	
	sz0 = s0;
	sz1 = s1;
	sz2 = s2;
	sz3 = s3;
	
	V3DLONG totalbytes = sz0*sz1*sz2*sz3*dt;
	data1d = (unsigned char*)Guarded_Malloc(totalbytes,"createBlankImage");
	
	if (!data1d)
	{
		NSLog(@"Fail to allocate memory in My4DImageSimple::createBlankImage(). Check your program. \n");
		sz0=sz1=sz2=sz3=0; datatype=V3D_UNKNOWN;
		b_error=1;
		return;
	}
	
	for (V3DLONG i=0;i<totalbytes;i++) data1d[i] = 0;
	
	return;
}

-(BOOL) isSameDataBuffer:(Image4DSimple *) p
{
	if (!p) return NO; // cannot be the same if the pointer to be compared is null
	if (data1d!=[p rawData])
		return NO; //the data of course are different if the pointers are different
	else //there is a chance that the data pointers are the same, but their sizes are different
	{
		if ([self totalBytes] == [p totalBytes])
			return NO;
		else return YES;
	}
}

-(unsigned char*) rawData
{
	return data1d;
}

-(V3DLONG) xDim
{
	return sz0;
}
-(V3DLONG) yDim
{
	return sz1;
}
-(V3DLONG) zDim
{
	return sz2;
}
-(V3DLONG) cDim
{
	return sz3;
}
-(V3DLONG) tDim
{
	return sz_time;
}

-(V3DLONG) validZSliceNum
{
	return valid_zslicenum;
}
-(V3DLONG) preValidZSliceNum
{
	return prevalid_zslicenum;
}

-(int) error
{
	return b_error;
}

-(TimePackType) timePackType
{
	return timepacktype;
}
-(ImagePixelType) imagePixelType
{
	return datatype;
}

-(V3DLONG) totalUnitNumber
{
	return sz0*sz1*sz2*sz3;
}
-(V3DLONG) totalUnitNumberPerPlane
{
	return sz0*sz1;
}
-(V3DLONG) totalUnitNumberPerChannel
{
	return sz0*sz1*sz2;
}

-(V3DLONG) unitBytes
{
	switch (datatype)
	{
		case V3D_UINT8: return 1;
		case V3D_UINT16: return 2;
		case V3D_FLOAT32: return 4;
		default: return 1;
	}
}
-(V3DLONG) totalBytes
{
	return [self unitBytes]*sz0*sz1*sz2*sz3;
}

-(unsigned char*) rawDataAtChannel:(V3DLONG) cid
{
	V3DLONG myid = cid; 
	if (myid<0) myid=0; 
	else if (myid>=sz3) myid = sz3-1;
	return data1d + myid*[self totalUnitNumberPerPlane]*[self unitBytes];
}
-(int) isSuccess
{
	if (sz0<=0 || sz1<=0 || sz2<=0 || sz3<=0) b_error=1; return !b_error;
}
-(BOOL) valid
{
	return (
			!data1d ||
			sz0<=0 ||
			sz1<=0 ||
			sz2<=0 ||
			sz3<=0 ||
			b_error ||
			(datatype!=V3D_UINT8 &&
			 datatype!=V3D_UINT16 &&
			 datatype!=V3D_FLOAT32)) ?  NO : YES;
}

-(double) rezX
{
	return rez_x;
}
-(double) rezY
{
	return rez_y;
}
-(double) rezZ
{
	return rez_z;
}

-(double) originX
{
	return origin_x;
}
-(double) originY
{
	return origin_y;
}
-(double) originZ
{
	return origin_z;
}

-(void) cleanExistData
{
	[self deleteRawDataAndSetPointerToNull];
	sz0 = sz1 = sz2 = sz3 = 0;
	sz_time = 0;
	datatype = V3D_UNKNOWN;
	timepacktype = TIME_PACK_NONE;
	imgSrcFile[0] = '\0';
	b_error = 0;
	rez_x = rez_y = rez_z = 1;
	valid_zslicenum = 0;
}

-(void) setError:(int) error
{
	b_error = error;
}

@end
